
package com.zcp.pcsuitall;

import android.content.Context;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 对外通讯接口，主要用来负责通讯。
 */
public class FileThread extends Thread {

    private int port = 8851;

    private String localIp = "127.0.0.1";

    private SocketService context = null;

    private SocketChannel ssc;

    private Object lock = new Object();

    private String fileName;
    
    private String fileId;

    private long fileLength = 0;
    
    private String isStop="not";

    public FileThread(String ip, int port, SocketService context) {
        localIp = ip;
        this.port = port;
        this.context = context;
    }

    
    public void setFileTranStop()
    {
        isStop="ok";
    }
    /**
     * 线程启动初始化socket，并且开始监听。
     */
    public void run() {
        try {
            Selector s = initializeSelector();
            while (true) {
                int n = s.select();
                if (n == 0) {// 没有指定的I/O事件发生
                    continue;
                }
                Iterator<SelectionKey> it = s.selectedKeys().iterator();
                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();
                    if (key.isAcceptable()) {// 侦听端信号触发
                        // 启动一个新的连接
                        acceptNewCon(key, s);
                    } else {
                        // 处理数据,每一个文件会产生一个通道，比如客户端发送5个文件，那么就会调用5次这个方法。
                        dealWithData(key, context);
                    }
                }
            }
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
    }

    /**
     * 接收客户端数据。
     * 
     * @param sc 连接通道。
     * @return
     */
    private void receiveData(SelectionKey key, Context context) {
        synchronized (lock) {
            if (fileName != null && fileLength != 0) {
                saveDataToFile((SocketChannel) key.channel(), fileName, fileLength);
            }
        }
    }

    public void closeSocketChannel(SelectionKey key) {
        synchronized (lock) {
//            SuitUtil.sendConnectionStatusMes(context,false);
            if (key != null) {
                try {
                    key.cancel();
                    key.channel().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public boolean downFile(String fileName, long fileLength,String id) {
        boolean result = true;
        File file = new File(fileName);
        if (file.exists() && file.isFile()) {
            result = file.delete();
        }
        this.fileName = fileName;
        this.fileLength = fileLength;
        this.fileId=id;
        return result;

    }

    /**
     * 向客户端发送文件数据。
     * 
     * @param filePath
     */
    public void sendFile(String filePath) {
        synchronized (lock) {
            FileInputStream fileInputStream = null;
            FileChannel inChannel = null;
            try {
                fileInputStream = new FileInputStream(filePath);
                inChannel = fileInputStream.getChannel();
                ByteBuffer w_buff = ByteBuffer.allocate(1024);
                while (true&&"not".equals(isStop)) {
                    int eof = inChannel.read(w_buff);
                    if (eof == -1)
                        break;
                    w_buff.flip();
                    EchoToClient(ssc, w_buff);
                    w_buff.clear();
                }
            } catch (Exception ioe) {
                ioe.printStackTrace();
            } finally {
                isStop="not";
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (inChannel != null) {
                    try {
                        inChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 初始化选择监听器。<br>
     * 
     * @return
     * @throws IOException
     */
    private Selector initializeSelector() throws IOException {
        // 生成一个侦听端
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // 将侦听端设为异步方式
        ssc.configureBlocking(false);
        // 生成一个信号监视器
        Selector s = Selector.open();
        // 侦听端绑定到一个端口
        ssc.socket().bind(new InetSocketAddress(localIp, port));
        // 设置侦听端所选的异步信号OP_ACCEPT
        ssc.register(s, SelectionKey.OP_ACCEPT);

        return s;
    }

    /**
     * 接受一个新的连接。
     * 
     * @param key
     * @param s
     * @throws IOException
     */
    private void acceptNewCon(SelectionKey key, Selector s) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        // 接受一个新的连接
        SocketChannel sc = server.accept();
        sc.configureBlocking(false);
        // 设置该socket的异步信号OP_READ:当socket可读时，
        sc.register(s, SelectionKey.OP_READ);

        ssc = sc;// 由于只有当个客户端连接，所以就保留一个。
    }

    /**
     * 当数据可读的时候就接收数据，并处理相应的结果。
     * 
     * @param key
     */
    private void dealWithData(SelectionKey key, Context context) {
        try {
            if (key.isReadable()) {// 某socket可读信号
                receiveData(key, context);
            }
        } catch (Exception e) {
            Log.e(TAG, "dealWithData  " + e.getMessage());
            closeSocketChannel(key);
        }
    }

    /**
     * 发送数据到通道客户端中。<br>
     * 
     * @param sc
     * @param write_buff
     * @throws IOException
     */
    private void EchoToClient(SocketChannel sc, ByteBuffer write_buff) throws IOException {
        while (write_buff.hasRemaining()) {
            sc.write(write_buff);
        }
    }

    private ByteBuffer r_buff = ByteBuffer.allocate(1024);

    private FileOutputStream fileOutputStream;

    private FileChannel outChannel;

    /**
     * 从通道中获取文件数据。
     * 
     * @param sc
     * @param path
     * @param fileLength
     */
    private void saveDataToFile(SocketChannel sc, String path, long myfileLength) {
        // Log.i("222", "saveDataToFile"+path);
        boolean result=true;
        try {
            fileOutputStream = new FileOutputStream(path, true);
            outChannel = fileOutputStream.getChannel();
            r_buff.clear();
            long count = 0;// 用来记录已经传输文件的大小
            int size = 0;
            boolean close = false;
            while (!close&&"not".equals(isStop)) {
                while ((size = sc.read(r_buff)) > 0) {
                    count = count + size;
                    // 确保r_buff可读
                    r_buff.flip();
                    if (count < myfileLength) {
                        outChannel.write(r_buff);
                    } else if (count == myfileLength) {
                        outChannel.write(r_buff);
                        close = true;
                        break;
                    } else {
                        // 防止最后一个缓存中数据大于文件
                        outChannel.write(r_buff, (size - (count - myfileLength) - 1));
                        close = true;
                        break;
                    }

                    r_buff.clear();
                }
            }
            close = false;
            count = 0;

        } catch (Exception e) {
            result=false;
            e.printStackTrace();
        } finally {
            isStop="not";
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            fileOutputStream = null;
            outChannel = null;
        }
        //扫描外部存储数据库中。
        SuitUtil.scanFile(context, path);
        // 通知本次接收文件已经结束，可以继续下一次发送。        
        returnSaveMessageOk(result);
        fileName = null;
        fileLength = 0;
        fileId=null;
        

    }

    /**
     * 通知客户端本次接收文件结束。
     */
    private void returnSaveMessageOk(boolean result) {
        try {
            StringBuilder returnMessage = new StringBuilder();
            returnMessage.append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>");
            returnMessage.append("<root><action>SaveFileOk</action><data>");
            returnMessage.append("<id>" + fileId + "</id>"); 
            returnMessage.append("<fileName>" + fileName + "</fileName>");
            returnMessage.append("<fileLength>" + fileLength + "</fileLength>");
            returnMessage.append("<key>" + port + "</key>");
            returnMessage.append("<result>" + result + "</result>");                      
            returnMessage.append("</data></root>");

            context.sendData(returnMessage.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String TAG = "FileThread";

}
